/** signals.d: A simple Signal-Solt pattern implemention

  Written in the D programming language 1.0

Authors:	
	Wei Li (oldrev@gmail.com)

Copyright:	
	Copyright (C) 2007 Wei Li.

License:	
	BSD

*/

module dotmars.base.signals;


import dotmars.base.typetraits;


// A stupid finding function, but works fine

private size_t find(T)(T[] arr, T value)
{
	for(size_t i = 0; i < arr.length; ++i) {
		if(arr[i] == value) return i;
	}
	return arr.length;
}


//Do We need the opCopy overloading?

struct Signal(ParameterTypes...)
{
	alias Signal!(ParameterTypes) SelfType;

	// function pointer can be converted to delegate, so  
   	alias void 
		delegate(ParameterTypes) DelegateType;

	private DelegateType[] m_delegates; //or a single way linked list?

	public void connect(DelegateType ds) 
	in {
		assert(ds !is null);
	}
	body {
		if(connected(ds))
				return;

		m_delegates ~= ds;
	}

	public void opAddAssign(DelegateType ds) 
	in {
		assert(ds !is null);
	}
	body {
		connect(ds);
	}

	public bool opIn_r(DelegateType lhs) 
	{
		//A small trick, so we can use it like this: if(lhs in mySignal) ... 

		return connected(lhs);
	}

	public void opCall(ParameterTypes args)
	{
		if(m_delegates.length == 0) return;
		foreach(dg; m_delegates)
		{
			if(dg !is null)
				dg(args);
		}
	}

	public void disconnect(DelegateType ds)
	in {
		assert(ds !is null);
	}
	body {
		size_t i = m_delegates.find(ds);
		if(i < m_delegates.length) { 
			m_delegates[i] = null; 
		}
	}

	public bool connected(DelegateType ds)
	in {
		assert(ds !is null);
	}
	body {
		size_t i = m_delegates.find(ds);
		if(i == m_delegates.length) return false;
		if(m_delegates[i] !is null)
			return true;
		return false;
	}

}
